use cmsis_rtos2_rs::static_mem::Mutex;
use periph_utils::stm32f1::stm32f103::{Interrupt, interrupt};
use periph_utils::stm32f1::stm32f103::NVIC;
use periph_utils::GpioConfig;
use periph_utils::stm32f1;
use utils::{BitSet, MutCell, VolatileHandle};



#[derive(GpioConfig)]
#[gpio(init = "gpio_init", 
    io(name = "pl", io = "PB3", mode = "OUT_PP", set, reset),
    io(name = "sck", io = "PB4", mode = "OUT_PP", set, reset),
    io(name = "q7", io = "PB5", mode = "IN_FLOAT", read),
    io(name = "flow", io = "PB1", mode = "IN_FLOAT", read, exti_down), // 流量计
    io(name = "ice_high", io = "PC4", mode = "IN_FLOAT", read),
    io(name = "ice_low", io = "PC5", mode = "IN_FLOAT", read),
    io(name = "water_high", io = "PC6", mode = "IN_FLOAT", read),
    io(name = "water_low", io = "PC7", mode = "IN_FLOAT", read),
)]
struct Pin;

struct Context {
    mutex: Mutex,
    flow_count: MutCell<u16>,
}

impl Context {

    const fn uninit() -> Self {
        Self {
            mutex: Mutex::uninit(),
            flow_count: MutCell::const_new(0)
        }
    }

    unsafe fn init_once(&self) {
        self.mutex.init_once("sensor");
    }
}

static CTX: Context = Context::uninit();

pub unsafe fn init() {
    Pin::gpio_init();
    CTX.init_once(); 
    NVIC::unmask(Interrupt::EXTI1);
}

pub fn flow_count_reset() {
    unsafe { CTX.flow_count.as_mut().volatile_write(0); }
}

#[inline(always)]
pub fn flow_ml(flow_arg: u32) -> u32 {
    let count = flow_count() as u32;
    count * 1000 / flow_arg
}

pub fn flow_count() -> u16 {
    CTX.flow_count.volatile_read()
}


pub fn is_water_high() -> bool {
    Pin::water_high_read()
}

pub fn is_water_low() -> bool {
    Pin::water_low_read()
}

pub fn is_pearl_checked() -> bool {
    read().is_set(0)
}

pub fn is_nozzle_origin() -> bool {
    read().is_set(1)
}

pub fn is_stir_top() -> bool {
    read().is_set(2)
}

pub fn is_stir_bottom() -> bool {
    read().is_set(3)
}

pub fn is_trun_left() -> bool {
    read().is_set(4)
}

pub fn is_trun_right() -> bool {
    read().is_set(5)
}

pub fn is_clamp_left() -> bool {
    read().is_set(6)
}

pub fn is_clamp_right() -> bool {
    read().is_set(7)
}

fn read() -> u8 {
    CTX.mutex.free(read_impl)
}

fn read_impl() -> u8 {
    let mut value: u8 = 0;
    Pin::pl_reset();
    Pin::pl_set();
    for _ in 0..8 {
        value <<= 1;
        if Pin::q7_read() {
            value |= 0x01;
        }
        Pin::sck_set();
        Pin::sck_reset();
    }
    value
}

#[interrupt]
unsafe fn EXTI1() {
    if Pin::flow_is_exti_pr() {
        Pin::flow_clear_exti_pr();
        CTX.flow_count.as_mut().volatile_add(1);
    }
}
















